package com.starsky.common.utils.word;

import com.starsky.common.utils.reflection.ReflectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

/**
 * @author  wansh
 * @des 数据导出成word工具
 * @date  2020/9/19 22:20
 * @version 1.0
 * @email 1057718341@qq.com
 */
public class WordUtil {

	private static String CN_FONT_FAMILY = "宋体";

	private static String EN_FONT_FAMILY = "Times New Roman";

	/**
	 * TODO 将word写到本地文件中
	 * 
	 */
	public static void writeWordFile(XWPFDocument docxDocument, String path) {
		FileOutputStream fos = null;
		try {
			// word写入到文件
			fos = new FileOutputStream(path);
			docxDocument.write(fos);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 写word
	 * 
	 * @throws IOException
	 */
	public static XWPFDocument export2Word(WordDataInfo dataInfo) throws IOException {
		XWPFDocument docxDocument = new XWPFDocument();
		// 写Word题目
		createSubject(docxDocument, dataInfo);
		// 创建目录页
		createCatalog(docxDocument);
		// 获取内容
		List<Title> titles = dataInfo.getTitles();
		for (TitleLevel level : TitleLevel.values()) {
			// 新建标题样式
			WordStyleUtil.addCustomHeadingStyle(docxDocument, level);
		}
		for (Title title : titles) {
			// 写入内容
			writeInfo(docxDocument, title, dataInfo);
		}
		return docxDocument;
	}

	/**
	 * TODO 创建目录页,仅仅是留出目录页,还需要手动添加目录(往后开发者可自行研究研究)
	 */
	private static void createCatalog(XWPFDocument docxDocument) {
		XWPFParagraph paragraph = docxDocument.createParagraph();
		paragraph.setPageBreak(true);
		// 固定值25磅
		WordStyleUtil
				.setParagraphSpacingInfo(paragraph, false, 0, 0, null, 100, false, 500, STLineSpacingRule.AT_LEAST);
		// 居中
		WordStyleUtil.setParagraphAlignInfo(paragraph, ParagraphAlignment.CENTER, TextAlignment.CENTER);

		XWPFRun run = WordFactory.getOrAddParagraphFirstRun(paragraph, false, false);
		WordStyleUtil.setParagraphRunFontInfo(paragraph, run, "宋体", "Times New Roman", 44, true, false, false, false,
				null, null, 0, 0, 100);
		run.setText("目	录");

		XWPFParagraph paragraphInfo = docxDocument.createParagraph();
		XWPFRun runInfo = WordFactory.getOrAddParagraphFirstRun(paragraphInfo, false, false);
		WordStyleUtil.setParagraphRunFontInfo(paragraph, runInfo, "宋体", "Times New Roman", 30, true, false, false,
				false, null, null, 0, 0, 100);
		runInfo.setText("点击引用手动添加目录");
		pageBreak(docxDocument);
	}

	/**
	 * TODO 写Word题目
	 */
	private static void createSubject(XWPFDocument docxDocument, WordDataInfo dataInfo) {
		XWPFParagraph titleParagraph = docxDocument.createParagraph();
		XWPFRun titleRun = WordFactory.getOrAddParagraphFirstRun(titleParagraph, true, true);
		// 居中
		WordStyleUtil.setParagraphAlignInfo(titleParagraph, ParagraphAlignment.CENTER, TextAlignment.CENTER);
		WordStyleUtil.setParagraphRunFontInfo(titleParagraph, titleRun, "宋体", "Times New Roman", 52, true, false,
				false, false, null, null, 0, 0, 100);
		titleRun.setText(dataInfo.getSubject());
	}

	/**
	 * TODO 换下一页
	 */
	private static void pageBreak(XWPFDocument docxDocument) {
		XWPFParagraph p2 = docxDocument.createParagraph();
		p2.setPageBreak(true);
	}

	/**
	 * TODO 写word内容
	 */
	private static void writeInfo(XWPFDocument docxDocument, Title title, WordDataInfo dataInfo) {
		int level = title.getTitleLevel().getValue();
		Map<Title, List<WordContent>> contentMap = dataInfo.getContent();
		XWPFParagraph paragraph = docxDocument.getLastParagraph();
		// 短路间距默认
		WordStyleUtil.setParagraphSpacingInfo(paragraph, true, 0, 80, null, null, true, 500, STLineSpacingRule.AUTO);
		// 居左
		WordStyleUtil.setParagraphAlignInfo(paragraph, ParagraphAlignment.LEFT, TextAlignment.CENTER);
		XWPFRun run = WordFactory.getOrAddParagraphFirstRun(paragraph, false, false);
		// 自号 二号
		WordStyleUtil.setParagraphRunFontInfo(paragraph, run, CN_FONT_FAMILY, EN_FONT_FAMILY, 52 - (level * 8), true,
				false, false, false, null, null, 0, 0, 100);
		run.setText(title.getTitleName());
		paragraph.setStyle(title.getTitleLevel().toString());
		if (contentMap.get(title) != null && contentMap.get(title).size() > 0) {
			for (WordContent content : contentMap.get(title)) {
				// 根据内容类型写内容
				if (content.getContentType().getValue() == 1) {
					// 文本类型
					writeTextInfo(docxDocument, content);
				} else if (content.getContentType().getValue() == 2) {
					// 图片类型

				} else if (content.getContentType().getValue() == 3) {
					// 表格
					writeTable(docxDocument, content);
				} else {

				}
			}
		}
		docxDocument.createParagraph();
		if (title.getChilds() != null && title.getChilds().size() > 0) {
			for (Title child : title.getChilds()) {
				writeInfo(docxDocument, child, dataInfo);
			}
		}
	}

	/**
	 * TODO 写表格到word
	 * @param docxDocument
	 */
	private static void writeTable(XWPFDocument docxDocument, WordContent wordContent) {
		Map<TableDesc, List<?>> tableInfos = wordContent.getTableInfo();
		for (Map.Entry<TableDesc, List<?>> entry : tableInfos.entrySet()) {
			// 创建表格题目
			createTableTitle(docxDocument, entry.getKey());
			XWPFTable table = docxDocument.createTable();
			// 表格属性
			CTTblPr tablePr = table.getCTTbl().addNewTblPr();
			tablePr.addNewJc().setVal(STJc.CENTER);
			// 表格宽度
			CTTblWidth width = tablePr.addNewTblW();
			width.setW(BigInteger.valueOf(8000));

			XWPFTableRow row = table.getRow(0);
			TableDesc tableDesc = entry.getKey();
			List<FiledDescription> descriptions = tableDesc.getFiledDescriptions();
			if (descriptions != null && descriptions.size() > 0) {
				for (int i = 0; i < descriptions.size(); i++) {
					// 表头
					FiledDescription description = descriptions.get(i);
					String fieldDesc = description.getFieldDesc();
					XWPFTableCell cell = null;
					if (i == 0) {
						cell = row.getCell(0);
					} else {
						cell = row.createCell();
					}
					// 创建单元格内容
					XWPFParagraph paragraph = WordFactory.getCellFirstParagraph(cell);
					paragraph.setAlignment(ParagraphAlignment.CENTER);
					XWPFRun run = paragraph.createRun();
					run.setBold(true);
					run.setText(fieldDesc);
					// 更改单元格长度
					CTTc cttc = cell.getCTTc();
					CTTcPr ctPr = cttc.isSetTcPr() ? cttc.getTcPr() : cttc.addNewTcPr();
					ctPr.addNewTcW().setW(BigInteger.valueOf(fieldDesc.getBytes().length * 200));
					ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
				}
			}
			List<?> data = entry.getValue();
			// 写表格里的内容
			writeTableInfo(table, descriptions, data);

		}
	}

	/**
	 * TODO 写表格里的内容
	 */
	@SuppressWarnings("unchecked")
	private static void writeTableInfo(XWPFTable table, List<FiledDescription> descriptions, List<?> data) {
		if (data != null && data.size() > 0) {
			for (Object object : data) {
				// 拿出每一个数据,一个数据为一行
				XWPFTableRow row2 = table.createRow();
				for (int i = 0; i < descriptions.size(); i++) {
					FiledDescription description = descriptions.get(i);
					String fieldName = description.getFieldName();
					String value = "";
					XWPFTableCell cell = row2.getCell(i);
					// 判断类型是Map还是Object
					if (object instanceof Map) {
						Map<String, Object> mapData = (Map<String, Object>) object;
						value = mapData.get(fieldName) == null ? "" : mapData.get(fieldName).toString();
					} else {
						value = ReflectionUtils.invokeGetterMethod(object, fieldName) == null ? "" : ReflectionUtils
								.invokeGetterMethod(object, fieldName).toString();
					}
					XWPFParagraph paragraph = WordFactory.getCellFirstParagraph(cell);
					paragraph.setAlignment(ParagraphAlignment.CENTER);
					XWPFRun run = paragraph.createRun();
					WordStyleUtil.setParagraphRunFontInfo(paragraph, run, CN_FONT_FAMILY, EN_FONT_FAMILY, 24, false,
							false, false, false, null, null, 0, 0, 100);
					run.setText(value);
				}
			}
		}
	}

	/**
	 * TODO 创建word表格题目
	 * 
	 */
	private static void createTableTitle(XWPFDocument docxDocument, TableDesc tableDesc) {
		if (StringUtils.isNotEmpty(tableDesc.getTableTitle())) {
			XWPFParagraph tableTitlePF = docxDocument.createParagraph();
			tableTitlePF.setAlignment(ParagraphAlignment.CENTER);
			XWPFRun tableTitleRun = tableTitlePF.createRun();
			tableTitleRun.setFontFamily(CN_FONT_FAMILY);
			tableTitleRun.setFontSize(10);
			tableTitleRun.setBold(true);
			tableTitleRun.setText(tableDesc.getTableTitle());
		}
	}

	/**
	 * TODO 写文本到word
	 * @param docxDocument
	 *            文本信息的list
	 */
	private static void writeTextInfo(XWPFDocument docxDocument, WordContent wordContent) {
		List<String> textInfo = wordContent.getTextInfo();
		if (textInfo != null && textInfo.size() > 0) {
			for (String content : textInfo) {
				XWPFParagraph contentPF = docxDocument.createParagraph();
				// 设置字段间隔
				WordStyleUtil.setParagraphSpacingInfo(contentPF, false, null, null, null, null, false, 500,
						STLineSpacingRule.AUTO);
				// 设置首行缩进
				WordStyleUtil.setParagraphIndInfo(contentPF, null, 200, null, null, null, null, null, null);
				XWPFRun contentRun = contentPF.createRun();
				WordStyleUtil.setParagraphRunFontInfo(contentPF, contentRun, CN_FONT_FAMILY, EN_FONT_FAMILY, 24, false,
						false, false, false, null, null, 0, 0, 100);
				contentRun.setText(content);
			}
		}
	}

}
